/**********************************************************************
 * 
 * Name: UpsertAccountREST
 * Object: Account
 * Purpose: Upsert Account from NC
 * Requirement:
 * Author: kittylau (382376269@qq.com)
 * Create Date: 2016-12-21
 * Modify History: 
        2017-01-12 据最新需求文档做出修改,增加ts字段
 * 
 * Url: /services/apexrest/CRM/upsertAccountREST
 * 接收的Json数据格式:
   {
    "data":[
        {
            "rowno":"行号",
            "custcode":"客户编码",
            "custname":"客户名称",
            "areaclcode":"所属地区编码",
            "areaclname":"所属地区名称",
            "conaddr":"通信地址",
            "zipcode":"邮政编码",
            "phone1":"电话",
            "fax1":"传真",
            "linkman1":"联系人",
            "mobilephone1":"手机",
            "email":"e-mail",
            "url":"web网址",
            "legalbody":"法人",
            "taxpayerid":"纳税人登记号",
            "zdtype":"终端类型0:经销商1：终端",
            "isgn":"是否国内Y:国内  N：国外",
            "addrname":"收货地址",
            "addrphone":"收货地址联系人",
            "addrlinkman":"收货地址电话",
            "banktypename":"银行类别",
            "accname":"开户银行",
            "account":"银行账号",
            "accountname":"账号名称",
            "currtypename":"币种"，
            "pk_cubasdoc":"客商主键"，
            "ts":"最后更新时间"
        },
        {...}
        ]
   }
*  返回的Json数据格式：
  {
    "result":"0 OR 1 , 1表示成功，0表示失败", 
    "result_msg":"成功为空，失败时为失败原因信息",
    "ts":"所有记录中,更新时间最近的那一条记录的更新时间"
  }
*************************************************************************/
@RestResource(urlMapping='/CRM/upsertAccountREST/*')
global without sharing class UpsertAccountREST {
    @HttpPost
    global static RestReturnMessage upsertAccount(List<AccountRestArgs> data) {
       RestReturnMessage message = null;
        try{
            if(data.size() > 0){
                message = doUpsertAccount(data);
            }else{
                throw new DmlException('没有数据');
            }
        }
        catch(Exception e){
            System.debug(LoggingLevel.INFO, '*** 错误信息: ' + e.getMessage() );
            System.debug(LoggingLevel.INFO, '*** 错误跟踪: ' + e.getStackTraceString());
            message = Utils.getRestReturnMessage(false,e.getMessage() + ' - ' + e.getStackTraceString()+Datetime.valueOf(Utils.MIN_DATE_TIME),new List<Map<String ,String>>());
        }
        System.debug(LoggingLevel.INFO, '*** 调用返回信息: ' + message);
        return message;
    }

    //得到POST数据，完成Account数据的插入或更新
    global static RestReturnMessage doUpsertAccount (List<AccountRestArgs> data) {
        RestReturnMessage message = null;
        Integer totalNum = data.size();
        Integer errNum = 0;
        Datetime maxTs = Datetime.valueOf(Utils.MIN_DATE_TIME);
        System.debug(LoggingLevel.INFO, '*** Account Data FROM NC: ' + data);

        //保存传过来的客户编号集合
        List<String> accCodesList = new List<String>();

        //保存传过来的客户名称集合
        Map<String,String> mapAccNames = new Map<String,String>();
        //保存传过来的客户简称集合
        Map<String,Account> mapExistAccShort = new Map<String,Account>();
        //保存传过来的客户记录类型集合
        Map<String,String> recordTypeList = new Map<String,String>();
        //保存传过来的联系人
        Map<String,String> contactList = new Map<String,String>();
        String shortName = '';
        for(AccountRestArgs acc : data){
            if(!String.isBlank(acc.custcode)){
                accCodesList.Add(acc.custcode);
                if(!mapAccNames.containsKey(acc.custname)){
                    mapAccNames.put(acc.custname,'');
                }
               /*
                shortName = getShortName(acc.custname);
                if(!mapExistAccShort.containsKey(shortName)){
                    mapExistAccShort.put(shortName,null);
                }
                */
                
                String rType = getRecordTypeName(acc.zdtype,acc.isgn);
                if(!recordTypeList.containsKey(rType)){
                    recordTypeList.put(rType,rType);
                }
                //保存联系人名称用来查询
                if(acc.linkman1 != null && !contactList.containsKey(acc.linkman1)){
                    contactList.put(acc.linkman1,'');
                }
                //如果当前记录的更新时间大于最大时间(maxTs)，则设置最大时间为当前记录时间
                Datetime dt = Utils.parseDatetime(acc.ts);
                if(dt > maxTs){
                    maxTs = dt;
                }
            }
        }
        System.debug('*** 本次传送客户号：' + accCodesList);
        System.debug('*** 本次传送客户名：' + mapAccNames);
        System.debug('*** 本次传送客户名(简称)：' + mapExistAccShort);
        System.debug('*** 本次客户联系人：' + contactList);

        //把已存在的Contact保存在Map中以用来查询
        Map<String,Id> mapExistcon = new Map<String,Id>();
        List<Contact> existContacts = [SELECT Id,Name FROM Contact WHERE NAME IN : contactList.keySet()];
        for(Contact con : existContacts){
            mapExistcon.put(con.Name,con.Id);
        }
        //用来保存或更新的列表集合
        List<Account> saveList = new List<Account>();
        List<Account> saveInsertList  = new List<Account>();
        //把已存在的客户保存在Map中以用来区别是新增或更新(按编码)
        Map<String,Account> mapExistAcc = new Map<String,Account>();
        List<Account> existAccounts = [SELECT Id,Name,RecordTypeId,AccountNumber,Address__c,Postcode__c,Phone,Fax,
                      SalesPIC__c,Email__c,Website,Artificial__c,TaxRegisterLicense__c,NCAccountNumber__c,
                      ShippingStreet,ShippingPostalCode,ShippingCity,ShippingCountry,
                      Area_Code__c,Area_Name__c,Currency_Name__c,Is_NC_Sync_Data__c, 
                      Bank_Type__c,Bank_Name__c,Bank_Account_No__c,Bank_Account_Name__c,NCICCode__c,IFuserule__c 
                FROM Account 
                WHERE AccountNumber IN :accCodesList 
                OR Name IN :mapAccNames.keySet()];
        //把已存在的客户保存在Map中以用来区别是新增或更新(按简称)//2017 5 26 按全称
        mapExistAccShort.clear();
        for(Account acc : existAccounts){
            mapExistAcc.put(acc.NCICCode__c, acc);
            //shortName = getShortName(acc.Name);
            if(!mapExistAccShort.containsKey(acc.Name)){
                mapExistAccShort.put(acc.Name,acc);
            }
        }
        System.debug('*** 客户编号在Salesforce中存在的：' + mapExistAcc);
        System.debug('*** 客户简称在Salesforce中存在的：' + mapExistAccShort);

        //得到所有的记录类型到Map集合
        Map<String,RecordType> mapRecordType = new Map<String,RecordType>();
        for(RecordType rt : [SELECT ID,Name FROM RecordType WHERE SobjectType = 'Account' and Name IN :recordTypeList.keySet()]){
            mapRecordType.put(rt.Name, rt);
        }
        //清除mapAccNames，用来记录客户名称(运行规格后的)和客户编码对应关系
        mapAccNames.clear();
        //记录简称重名的错误信息
        String errMessage = '';
        Integer iCount = 0;
           ///用来保存从表pk的记录集合
        	List<Map<String,String>> pkList = new List<Map<String,String>>();
        //新建或更新现存Acccount的字段值
        for(AccountRestArgs acc : data){
            //如果客户代码存在，并且zdtype=0或1（0或1是客户，其它为供应商）
            if(!String.isBlank(acc.pk_cubasdoc) && !String.isBlank(acc.zdtype) && (acc.zdtype.trim() =='0' || acc.zdtype.trim() == '1')){
               // shortName = getShortName(acc.custname);
                Account itemForSave = null;
                    /*
                    Postcode__c //邮政编码    
                    Address__c//通信地址
                Phone //电话 
                Fax //传真
   Email__c//电子邮件
                 Website //web网址 --> 网址
                    这些字段如果存在 则不更新 如果不存在则更新;
                    */
                //如果客户编号或客户简称已存在则取出更新
                if(mapExistAcc.containsKey(acc.pk_cubasdoc) || mapExistAccShort.containsKey(acc.custname)){
                    if(mapExistAcc.containsKey(acc.pk_cubasdoc)){
                        itemForSave = mapExistAcc.get(acc.pk_cubasdoc);
                    }else{
                        itemForSave = mapExistAccShort.get(acc.custname);

                    }
                   itemForSave.IFuserule__c = !itemForSave.IFuserule__c;//如果存在绕过验证规则

                }else{
                    
                    /*if(mapAccNames.containsKey(shortName)){
                        errMessage += errMessage == '' ? acc.pk_cubasdoc + '-' + acc.custname : ';' + acc.pk_cubasdoc + '-' + acc.custname;
                        errNum = errNum + 1;
                        continue;
                    }else{
                        mapAccNames.put(shortName,acc.pk_cubasdoc);

                    }*/
                                 itemForSave = new Account();

                }
                //客户名称最大80个字符
                String custN = '';
                if(acc.custname != null){
                    custN = acc.custname;
                    if(custN.length() > 79){
                        custN = custN.substring(0, 78);
                    }
                }
                //这个标记一定要设置为真才能插入或更新，不然会触发【NotEditNameAndArtificialFields】这个验证规则
                itemForSave.Is_NC_Sync_Data__c = true;
                itemForSave.RecordType = mapRecordType.get(getRecordTypeName(acc.zdtype,acc.isgn));
                itemForSave.RecordTypeId = itemForSave.RecordType.Id;
                itemForSave.AccountNumber = acc.custcode;//客户编码可以修改
                itemForSave.NCAccountNumber__c = acc.custcode;//客户编码(不能修改)
                itemForSave.Name = custN;//客户名称
                if(itemForSave.Address__c == null ){
                itemForSave.Address__c = acc.conaddr;//通信地址
                }                
                if( itemForSave.Postcode__c == null ){
                itemForSave.Postcode__c = acc.zipcode;//邮政编码
                }
                if(itemForSave.Phone == null ){
                itemForSave.Phone = acc.phone1;//电话 
                }
                if( itemForSave.Fax == null ){
                itemForSave.Fax = acc.fax1;//传真
                }
                itemForSave.SalesPIC__c = (mapExistcon.containsKey(acc.linkman1)?mapExistcon.get(acc.linkman1):null);//联系人-->销售责任人
                //itemForSave.SalesPICPhone__c = acc.mobilephone1;//手机-->销售责任人手机
                if( itemForSave.Email__c == null){
                itemForSave.Email__c = acc.email;//电子邮件
                }
                if( itemForSave.Website == null){
                itemForSave.Website = acc.url;//web网址 --> 网址
                } 
                if( itemForSave.Artificial__c == null){
                itemForSave.Artificial__c = acc.legalbody;//法人
                }
                itemForSave.TaxRegisterLicense__c = acc.taxpayerid;//纳税人登记号
                //收货地址
                itemForSave.ShippingStreet = acc.addrname;//收货地址 ??
                itemForSave.ShippingPostalCode = acc.zipcode;//收货邮政编码 
                itemForSave.ShippingCity = acc.addrphone;//收货电话
                itemForSave.ShippingCountry = acc.addrlinkman;//收货联系人
                itemForSave.Area_Code__c = acc.areaclcode;//所属地区编码
                itemForSave.Area_Name__c = acc.areaclname;//所属地区名称
                itemForSave.Bank_Type__c = acc.banktypename;//银行类别
                itemForSave.Bank_Name__c = acc.accname;//开户银行
                itemForSave.Bank_Account_No__c = acc.account;//银行账号
                itemForSave.Bank_Account_Name__c = acc.accountname;//账号名称
                itemForSave.Currency_Name__c  = acc.currtypename;//币种
                itemForSave.NCICCode__c = acc.pk_cubasdoc;//客商主键
				itemForSave.BillingType__c = acc.swkpfs;//生物开票方式

                iCount = iCount +1;
                  ///拼接返回的主表pk 和字表pk 
                    Map<String,String> pk = new Map<String,String>();
                    pk.put('mainpk',acc.pk_cubasdoc);
                    pk.put('sonpk','custbaseInfoPK');

                    pkList.add(pk);
                
               if (itemForSave.Id == null ) {
                    saveList.add(itemForSave);
                } else {
                   saveInsertList.add(itemForSave);

                }
                    
            }else{
                ///拼接返回的主表pk 和字表pk 
                    Map<String,String> pk = new Map<String,String>();
                    pk.put('mainpk',acc.pk_cubasdoc);
               		pk.put('sonpk','custbaseInfoPK');

                 	pkList.add(pk);
                errNum = errNum + 1;
            }
            
        }
        //设置事务还原点，当操作失败时用来回滚
        SavePoint sp = Database.setSavePoint();
        try{
            System.debug(saveList);
            if(saveList.size() > 0)Upsert saveList NCICCode__c;
            if (saveInsertList.size() >0)Update saveInsertList;
            String msg = '';

           /* List<Database.UpsertResult> res_lists = Database.upsert(saveList,false);
            String error = '';
            for(Database.UpsertResult u : res_lists){
            	if(u.getErrors() !=null){
                	error += u.getErrors() +';';
                }
            }
            if(error.length()>0){
            	
            	return message =Utils.getRestReturnMessage(false,error,Datetime.valueOf(Utils.MIN_DATE_TIME));
            }
            */
            //如果有简称重名
            if(errNum > 0){
                msg = '接受记录总数为: {0}条;成功处理记录: {1};错误记录总数: {2};错误记录编码和名称: {3}';
                msg = String.format(msg, new List<String>{totalNum.format(),(totalNum - errNum).format(),errNum.format(),errMessage});
            }else{
                msg = String.format('接受记录(总条数: {0}/成功处理：{1})都已经成功处理！',new List<String>{totalNum.format(),iCount.format()});
            }
            message = Utils.getRestReturnMessage(true,msg,pkList);
        }
        catch(Exception e) {
            System.debug(LoggingLevel.INFO, '*** 错误信息: ' + e.getMessage() );
            System.debug(LoggingLevel.INFO, '*** 错误跟踪: ' + e.getStackTraceString());
            //保存数据失败，回滚事务
            Database.rollback(sp);
            message =  Utils.getRestReturnMessage(false,e.getMessage() + ' - ' + e.getStackTraceString()+'时间:'+datetime.now().format(),new List<Map<String ,String>>());
        }
        //重新取出数据，设置Is_NC_Sync_Data__c = false
        try{
            List<String> ids  = new List<String>();
            for(Account acc : saveList){
                ids.add(acc.Id);
            }
            List<Account> upNcSync = [SELECT Id,Is_NC_Sync_Data__c,IFuserule__c FROM Account WHERE Id IN :ids];
            for(Account acc : upNcSync){
                acc.IFuserule__c = !acc.IFuserule__c;
                acc.Is_NC_Sync_Data__c = false;
            }
            Update upNcSync;
        }catch(Exception ex){
            system.debug('*** 更新Is_NC_Sync_Data__c TO False Error:' + ex.getMessage() + '\n' + ex.getStackTraceString());
        }
        return message; 
    }
    /*
        描述：按重名检测规格重新生成的客户简称,根据系统要求，客户简称不能重名
        参数：name - 客户名称
        返回：客户简称
    */
    global static String getShortName(String name){
        String custN = '';
        if(!String.isBlank(name)){
            custN = name;
        }
        if(custN.length() > 79){
            custN = custN.substring(0, 78);
        }
        //return custN.replace('九','9').replace('八','8').replace('七','7').replace('六','6').replace('五','5').replace('四','4').replace('三','3').replace('二','2').replace('一','1').replace('计划生育','计生').replace('中心血站','血站').replace('药品检验','药监').replace('质量检验','质检').replace('疾病预防控制中心','疾控').replace('疾病控制中心','疾控').replace('附属','').replace('股份','').replace('责任','').replace('有限','').replace('商贸','').replace('中医医','中医').replace('省','').replace('市','').replace('县','').replace('区','');
        return custN.replace('九','9').replace('八','8').replace('七','7').replace('六','6').replace('五','5').replace('四','4').replace('三','3').replace('二','2').replace('一','1').replace('零','0').replace('〇','0');
    }
    /*
        描述：得到记录类型名
        参数：
            zdtype:终端客户类型(0:经销商,1:终端客户)
            isgn：是否国内客户(Y/N)
        返回：返回Salesforce中对应的记录类型名
    */
    global static String getRecordTypeName(String zdtype,String isgn){
        String typ = (zdtype == null ? '2' : zdtype.trim());
        String tIsgn = (isgn == null ? 'Y' : isgn.trim());
        //国内客户
        if(tIsgn.trim() == 'Y'){
            return typ == '0' ? '经销商' : typ == '1'? '终端客户' : '公共关系';
        }
        else{ //国外客户
            return typ == '0' ? '海外经销商' : typ == '1'? '海外终端客户' : '海外公共关系';
        }
    }
    //根据NC提供的JSON结构来确定的Account字段集合
    global class AccountRestArgs {
        global String rowno; //行号
        global String custcode; //客户编码
        global String custname; //客户名称
        global String areaclcode; //所属地区编码
        global String areaclname; //所属地区名称
        global String conaddr; //通信地址
        global String zipcode; //邮政编码
        global String phone1; //电话
        global String fax1; //传真
        global String linkman1; //联系人
        global String mobilephone1; //手机
        global String email; //e-mail
        global String url; //web网址
        global String legalbody; //法人
        global String taxpayerid; //纳税人登记号
        global String zdtype; //终端类型 0:经销商 1：终端客户
        global String isgn; //是否国内 Y:国内  N：国外
        global String addrname; //收货地址
        global String addrphone; //收货电话
        global String addrlinkman; //收货联系人
        global String banktypename; //银行类别
        global String accname; //开户银行
        global String account; //银行账号
        global String accountname; //账号名称
        global String currtypename; //币种
        global String pk_cubasdoc; //客商主键
        global String ts;//本条记录最后更新时间
        global String swkpfs;//生物开票方式
    }
}